package com.faxsun.web.endpoint.live;

import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import mblog.web.formatter.JsonUtils;
import mtons.modules.pojos.Data;
import mtons.modules.pojos.Page;
import mtons.modules.pojos.UserContextHolder;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import com.faxsun.core.persist.entity.FollowListPO;
import com.faxsun.core.persist.entity.LiveMsgPO;
import com.faxsun.core.persist.entity.LivePO;
import com.faxsun.core.persist.entity.UserPO;
import com.faxsun.core.pojos.enums.FollowListType;
import com.faxsun.core.service.CommentService;
import com.faxsun.core.service.FollowListService;
import com.faxsun.core.service.LiveMsgService;
import com.faxsun.web.endpoint.entity.LiveMsgContent;
import com.faxsun.web.endpoint.entity.LiveMsgJSON;
import com.faxsun.web.endpoint.entity.LiveMsgsJSON;
import com.faxsun.web.pojos.FSUserProfile;
import com.faxsun.web.utils.WechatApiUtils;

@RestController
@RequestMapping("/api/v1/live")
public class LiveMsgEndpoint {

	private static final Logger log = LoggerFactory
			.getLogger(LiveMsgEndpoint.class);
	@Autowired
	private LiveMsgService liveMsgService;
	
	@Autowired
	private WechatApiUtils wechatApi;
    
    @Autowired
    private FollowListService flService;
    
    @Autowired
    private CommentService commentService;
	

	private final Map<String, DeferredResult<Data>> postRequest = new ConcurrentHashMap<String, DeferredResult<Data>>();

	/**
	 * <code>
	 * 	http://www.faxsun.com/faxsun-info/api/v1/live/history?channelid=1
	 * </code>
	 * <br>
	 * 可选参数:
	 * 
	 * <pre>
	 *     msgid,在msgId之前的消息
	 *     pagesize,需获取的消息数
	 *     pn, 第n页
	 * </pre>
	 * 
	 * @param msgId
	 *            消息ID，在msgId之前的消息
	 * @param channelId
	 *            频道ID
	 * @param pageSize
	 *            页大小，需获取的消息数
	 * @param pageNo
	 *            页码，第n页
	 * @return
	 */
	@Transactional
	@RequestMapping(value = "/history", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
	public Data list(
			@RequestParam(required = false, defaultValue = "0", value = "msgid") Long msgId,
			@RequestParam(value = "channelid", required = false) Long channelId,
			@RequestParam(required = false, value = "pagesize", defaultValue = "30") Integer pageSize,
			@RequestParam(required = false, value = "pn", defaultValue = "1") Integer pageNo) {
		Data ret = Data.failure("获取直播历史信息失败");

		if (channelId != null) {

			Page page = new Page(pageSize);
			page.setPageNo(pageNo);

			try {
				List<LiveMsgPO> result = liveMsgService.listPage(page,
						channelId, msgId);
				if (result == null) {
					ret.setMessage("频道Id不存在");
				} else {

					LiveMsgsJSON messages = LiveMsgsJSON.parse(page);
					messages=clearUndownloadedImage(messages);
					ret = Data.success(messages);
				}

			} catch (Exception e) {
				log.error("List history ", e);
			}
		} else {
			ret.setMessage("频道Id非法");
		}
		return ret;
	}

	/**
	 * 获取msgId之后的最新直播信息
	 * <code>http://www.faxsun.com/faxsun-info/api/v1/live/newMsg?channelid=1</code>
	 * 
	 * @param msgId
	 *            可为0或负数，此时获取最新的30条直播消息；msgId>0时，获取大于msgId的所有直播消息
	 * @param channelId
	 * @return <pre>
	 * 	{
	 *     "code": 0, 
	 *     "message": "操作成功", 
	 *     "data": {
	 *         "total": 2, 
	 *         "pageNo": 1, 
	 *         "pageSize": 2, 
	 *         "maxPage": 1, 
	 *         "msgs": [
	 *             {
	 *                 "id": 1, 
	 *                 "content": {
	 *                     "text": "123", 
	 *                     "url": [ ]
	 *                 }, 
	 *                 "user": {
	 *                     "name": "songdragon", 
	 *                     "openId": "123", 
	 *                     "avatar": "/src/img/avatar/mars/2.png", 
	 *                     "type": null
	 *                 }, 
	 *                 "channelId": 3, 
	 *                 "date": "2015-06-19"
	 *             }, 
	 *             {
	 *                 "id": 2, 
	 *                 "content": {
	 *                     "text": "123", 
	 *                     "url": [ ]
	 *                 }, 
	 *                 "user": {
	 *                     "name": "songdragon", 
	 *                     "openId": "123", 
	 *                     "avatar": "/src/img/avatar/mars/2.png", 
	 *                     "type": null
	 *                 }, 
	 *                 "channelId": 3, 
	 *                 "date": "2015-06-19"
	 *             }
	 *         ]
	 *     }
	 * }
	 * </pre>
	 */
	@Transactional
	@RequestMapping(value = "/newMsg", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
	public Data listNewMsg(
			@RequestParam(required = false, defaultValue = "0", value = "msgid") Long msgId,
			@RequestParam(value = "channelid", required = false) Long channelId) {
		Data ret = Data.failure("获取直播最新信息失败");

		if (channelId != null) {
			Page page = new Page(30);

			try {
				liveMsgService.listNewMsg(page, channelId, msgId);

				LiveMsgsJSON messages = LiveMsgsJSON.parse(page);
				messages=clearUndownloadedImage(messages);
				
				ret = Data.success(messages);

			} catch (Exception e) {
				log.error("List history ", e);
			}
		} else {
			ret.setMessage("频道Id非法");
		}
		return ret;
	}

	/**
	 * 异步获取msgId之后的最新直播信息，用于long-polling
	 * <code>http://www.faxsun.com/faxsun-info/api/v1/live/newMsgAsync?channelId=1</code>
	 * 该方法需要Servlet3.0支持
	 * 
	 * @param msgId
	 *            可为0或负数，此时获取最新的30条直播消息；msgId>0时，获取大于msgId的所有直播消息
	 * @param channelId
	 * @return
	 */
	@RequestMapping(value = "/newMsgAsync", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
	public DeferredResult<Data> listNewMsgAsync(
			@RequestParam(required = false, defaultValue = "0", value = "msgid") Long msgId,
			@RequestParam(value = "channelid") Long channelId,
			HttpSession session) {

		DeferredResult<Data> dr = new DeferredResult<Data>(10);

		Data ret = Data.failure("获取直播最新信息失败");
		dr.setResult(ret);
		final String sessionId = session.getId();

		if (sessionId == null) {
		} else {

			// 当DeferredResult对客户端响应后将其从列表中移除
			dr.onCompletion(new Runnable() {

				@Override
				public void run() {
					postRequest.remove(sessionId);
				}
			});
			postRequest.put(sessionId, dr);

		}
		return dr;
	}

	/**
	 * 发布直播消息,调用此方法时，ajax需使用form或设置content-type为application/x-www-form-
	 * urlencoded
	 * 
	 * @param form
	 *            共四个字段
	 * 
	 *            <pre>
	 *            channelId：频道列表
	 *            user.id: 用于验证
	 *            content.text:文字内容
	 *            content.url[0]:第一张图片
	 *            content.url[1]:第二张图片
	 *            ...
	 * </pre>
	 * 
	 *            说明：图片以数组形式命名
	 * @param result
	 *            BindingResult,用于验证错误
	 * @return JSON格式的返回结果：
	 * 
	 *         <pre>
	 * 	{
	 *     "code": 0,
	 *     "message": "操作成功",
	 *     "data": {
	 *         "id": 5,
	 *         "content": {
	 *             "text": "123",
	 *             "url": []
	 *         },
	 *         "user": {
	 *             "name": "songdragon",
	 *             "openId": "123",
	 *             "avatar": "/src/img/avatar/mars/2.png",
	 *             "type": null
	 *         },
	 *         "channelId": 3,
	 *         "date": "2015-06-18"
	 *     }
	 * }
	 * </pre>
	 */
	@RequestMapping(value = "/post", method = RequestMethod.POST, produces = "application/json;charset=UTF-8", consumes = "application/x-www-form-urlencoded")
	public Data post(@ModelAttribute("liveMsgJSON") LiveMsgJSON form,
			BindingResult result, HttpServletRequest request) {
		Data ret = Data.failure("发布直播消息失败，请稍后再试！");

		// 1. validate form
		LiveMsgPO msgPO = validate(form, result);
		// 2. persist form
		if (msgPO != null) {
			this.liveMsgService.save(msgPO);
			// 3. notify all online users
			if (msgPO.getId() > 0L) {
				LiveMsgJSON msg = LiveMsgJSON.parse(msgPO);
				ret = Data.success(msg);
				
				//通知其他观看直播的客户端
				Set<String> keys = postRequest.keySet();
				for (String key : keys) {
					postRequest.get(key).setResult(ret);
				}
			} else {
				ret.setMessage("发布直播消息失败，请检查用户id和频道id");
			}
		} else {
			//ret.setMessage("请检查提交内容");
			ret.setMessage(result.getFieldErrors().get(0).getDefaultMessage());
		}

		return ret;
	}
	
	/**
	 * 点赞直播消息,调用此方法时，ajax需使用form或设置content-type为application/x-www-form-urlencoded
     * url路径为/api/vi/live/thumbsup/msgid，其中msgid是前端获得的直播消息id，返回点赞后的点赞数量
	 * @param msgid
	 * @return 点赞后的该直播消息的点赞数量
	 */
	@RequestMapping(value = "/thumbsup/{msgid}", method = RequestMethod.POST, consumes = "application/x-www-form-urlencoded")
    @ResponseBody
	public Integer thumbsUp(@PathVariable Long msgid){
	    LiveMsgPO msg = liveMsgService.findById(msgid);
	    FSUserProfile up = (FSUserProfile) UserContextHolder.getUserProfile();
	    if(msg != null && up != null){
	       FollowListPO fl = new FollowListPO();
	       fl.setFollower_id(up.getId());
	       fl.setItem_type(FollowListType.LIVEMSG.getIntValue());
	       fl.setUid(msgid);
	       
	       flService.thumbsup(fl);
	       
	       int cnt = thumbsCnt(msgid);
	       return cnt;
	    }else{
	       return 0; 
	    }
	}
    
    /**
     * 取消点赞直播消息,调用此方法时，ajax需使用form或设置content-type为application/x-www-form-urlencoded
     * url路径为/api/vi/live/thumbscancel/msgid，其中msgid是前端获得的直播消息id，返回取消点赞后的点赞数量
     * @param msgid
     * @return 取消点赞后的该直播消息的点赞数量
     */
    @RequestMapping(value = "/thumbscancel/{msgid}", method = RequestMethod.POST)
    @ResponseBody
    public Integer thumbsCancel(@PathVariable Long msgid){
        LiveMsgPO msg = liveMsgService.findById(msgid);
        FSUserProfile up = (FSUserProfile) UserContextHolder.getUserProfile();
        if(msg != null && up != null){
           FollowListPO fl = flService.findFollow(msgid, up.getId(), FollowListType.LIVEMSG.getIntValue());
           if(fl == null){
              return 0; 
           }else{               
              flService.thumbsupCancel(fl);
              
              int cnt = thumbsCnt(msgid);
              return cnt;           
           }
        }else{
           return 0; 
        }
    }
    
    /**
     * 获取该条直播消息的点赞数量,调用此方法
     * url路径为/api/vi/live/thumbscnt/msgid，其中msgid是前端获得的直播消息id，返回该条直播消息的点赞数量
     * @param msgid
     * @return 该直播消息的点赞数量
     */
    @RequestMapping(value = "/thumbscnt/{msgid}", method = RequestMethod.GET)
    @ResponseBody
    public Integer thumbsCnt(@PathVariable Long msgid){
        LiveMsgPO msg = liveMsgService.findById(msgid);
        if(msg != null){
           Integer cnt = flService.countAllMyThumbsupers(msgid, FollowListType.LIVEMSG.getIntValue());
           if(cnt == null){
              return 0; 
           }else{
              return cnt;               
           }
        }else{
           return 0; 
        }
    }
    
    /**
     * 获取该条直播消息的评论数量,调用此方法
     * url路径为/api/vi/live/commentscnt/msgid，其中msgid是前端获得的直播消息id，返回该条直播消息的评论数量
     * @param msgid
     * @return 该直播消息的评论数量
     */
    @RequestMapping(value = "/commentscnt/{msgid}", method = RequestMethod.GET)
    @ResponseBody
    public Integer commentsCnt(@PathVariable Long msgid){
        LiveMsgPO msg = liveMsgService.findById(msgid);
        if(msg != null){
           Long cnt = commentService.count(msgid, FollowListType.LIVEMSG.getIntValue());
           if(cnt == null){
              return 0; 
           }else{
              return cnt.intValue();               
           }
        }else{
           return 0; 
        }
    }

	/**
	 * 检查发布直播表单项
	 * 
	 * @param form
	 * @param errors
	 * @return
	 */
	private LiveMsgPO validate(LiveMsgJSON form, BindingResult errors) {
		/*
		 * if (form.user == null ||
		 * StringUtils.isEmpty(form.getUser().getOpenId())) { FieldError error =
		 * new FieldError("LiveMsgForm", "openId", "用户id非法");
		 * errors.addError(error); }
		 */

		//TODO:验证当前用户id和发送者id
		if (form.getUser().getId() < 1) {
			FieldError error = new FieldError("LiveMsgForm", "id", "用户id非法");
			errors.addError(error);
		}

		if (StringUtils.isEmpty(form.channelId)) {
			FieldError error = new FieldError("LiveMsgForm", "channelId",
					"频道id非法");
			errors.addError(error);
		}

		if (form.content == null
				|| StringUtils.isEmpty(form.getContent().getText())
				&& form.getContent().getUrl().size() == 0) {
			FieldError error = new FieldError("LiveMsgForm", "text",
					"请输入文字、图片或者图文");
			errors.addError(error);
		}
		else if(form.getContent().getText()!=null && form.getContent().getText().length()>300){
			FieldError error = new FieldError("LiveMsgForm", "text.long",
					"亲，您发的文字过多，超过300字，请修改后再尝试发送！");
			errors.addError(error);
			
		}

		if (form.content != null && form.getContent().getUrl().size() > 0) {
			for (String imgUrl : form.getContent().getUrl()) {
				if (StringUtils.isEmpty(imgUrl)) {
					log.warn("There is url is empty! " + form.toString());
					FieldError error = new FieldError("LiveMsgForm", "text",
							"请输入文字、图片或者图文");
					errors.addError(error);
					break;
				}
			}
		}

		if (!errors.hasErrors()) {
			LiveMsgPO po = new LiveMsgPO();
			LivePO channel = new LivePO();
			channel.setId(form.channelId);
			po.setChannel(channel);

			

			po.setDate(new Date(System.currentTimeMillis()));

			UserPO sender = new UserPO();
			sender.setId(form.getUser().getId());
			po.setSender(sender);
			
			//替换url中的media_id为url
			LiveMsgContent content=triggerDownloadImages(form.getContent());
			form.setContent(content);
			
			po.setContent(JsonUtils.toJson(form.getContent()));
			return po;

		}

		return null;
	}

	/**
	 * 调用wechat服务器，下载图片，wechat服务器返回的为图片url
	 * @param content
	 * @return
	 */
	private LiveMsgContent triggerDownloadImages(LiveMsgContent content) {
		List<String> urls = content.getUrl();
		for(int i=0;i<urls.size();i++){
			String url=urls.get(i);
			if(!url.contains("/")){
				//media_id
				String imageUrl=wechatApi.getMediaUrl(url);
				if(!StringUtils.isEmpty(imageUrl)){
					urls.set(i, imageUrl);
				}
			}
		}
		
		return content;
		
	}
	
	/**
	 * 移除MsgsJson中的非法Url
	 * @param messages
	 * @return
	 */
	private LiveMsgsJSON clearUndownloadedImage(LiveMsgsJSON messages){
		List<LiveMsgJSON> msgs = messages.msgs;
		for(LiveMsgJSON msg:msgs){
			List<String> url = msg.getContent().url;
			Iterator<String> it = url.iterator();
			while (it.hasNext()) {
				String u = it.next();
				if (u.startsWith("http://") || u.startsWith("https://")) {
					continue;
				} else {
					it.remove();
				}
			}
			msg.getContent().url=url;
		}
		messages.msgs=msgs;
		return messages;
	}
}
